﻿using AgCIM.Tools.Maths.Numerics;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CarSimulate
{
    internal class RoadManager
    {
        private List<TrafficLine> m_allLines = new List<TrafficLine>();
        private List<TrafficNode> m_allNodes = new List<TrafficNode>();

        internal List<TrafficLine> AllLines { get => m_allLines; set => m_allLines = value; }
        internal List<TrafficNode> AllNodes { get => m_allNodes; set => m_allNodes = value; }
        public List<PointF> AllNodes2 = new List<PointF>();

        public void Initilize()
        {
            if (AllLines.Count == 0)
            {
                AllLines = new List<TrafficLine>()
                     {
                        new TrafficLine() { StartPoint = new Point(10, 10), EndPoint = new Point(10, 400),LinePId=0 },
                         new TrafficLine() { StartPoint = new Point(40, 10), EndPoint = new Point(40, 400),LinePId=0},
                         new TrafficLine() { StartPoint = new Point(10, 400), EndPoint = new Point(100, 820),LinePId=1 },
                         new TrafficLine() { StartPoint = new Point(40, 400), EndPoint = new Point(140, 800),LinePId=1 },
                          new TrafficLine() { StartPoint = new Point(100, 820), EndPoint = new Point(400, 820),LinePId=2 },
                         new TrafficLine() { StartPoint = new Point(140, 800), EndPoint = new Point(400, 800),LinePId=2 },
                         new TrafficLine() { StartPoint = new Point(40, 400), EndPoint = new Point(100, 400),LinePId=3 },
                         new TrafficLine() { StartPoint = new Point(100, 400), EndPoint = new Point(100, 40),LinePId=4 },
                     };
            }
            List<PointCluster> pc = new List<PointCluster>();
            for (var i = 0; i < AllLines.Count; i++)
            {
                pc.Add(new PointCluster(AllLines[i].StartPoint,i,true));
                pc.Add(new PointCluster(AllLines[i].EndPoint, i, false));
            }
            while (true)
            {
                for(var i=0;i<pc.Count;i++)
                {
                    if (pc[i].IsDisposed) continue;
                    for (var j = i+1; j < pc.Count; j++)
                    {
                        if (pc[j].IsDisposed) continue;
                        double dx = Math.Abs(pc[i].Center.X - pc[j].Center.X)+ Math.Abs(pc[i].Center.Y - pc[j].Center.Y);
                        if (dx < 6)
                        {
                            pc[i].Union(pc[j]);
                        }
                    }
                }
                bool hasUpdate = false;
                for(var i=pc.Count-1; i>=0; i--)
                {
                    if (pc[i].IsDisposed)
                    {
                        pc.RemoveAt(i);
                        hasUpdate = true;
                    }
                }
                if (hasUpdate == false)
                {
                    break;
                }
            }
            for (var i = 0; i < pc.Count; i++)
            {
                if (pc[i].PS.Count == 1)
                {
                    var minDis = double.MaxValue;
                    for (var j = 0; j < pc.Count; j++)
                    {
                        if (i != j)
                        {
                            var dis = Math.Sqrt((pc[i].Center.X - pc[j].Center.X)* (pc[i].Center.X - pc[j].Center.X)+
                                (pc[i].Center.Y - pc[j].Center.Y) * (pc[i].Center.Y - pc[j].Center.Y));
                            minDis= minDis>dis ? dis : minDis;
                        }
                    }
                }
            }

            for (var i = 0; i < pc.Count; i++)
            {
                AllNodes2.Add(pc[i].Center);
                for (var j = 0; j < pc[i].PS.Count; j++)
                {
                    var li = pc[i].PS[j].LineIndex;
                    var isStart = pc[i].PS[j].IsStart;
                    if (isStart)
                        AllLines[li].StartPointKey = i;
                    else
                        AllLines[li].EndPointKey = i;
                }
            }
            for (var i = AllLines.Count - 1; i >= 0; i--)
            {
                if (AllLines[i].StartPointKey == AllLines[i].EndPointKey)
                {
                    AllLines.RemoveAt(i);
                }
            }

            //寻找下一个路段
            for (var i = 0; i < AllLines.Count; i++)
            {
                var line1 = AllLines[i];
                for (var j = 0; j < AllLines.Count; j++)
                {
                    var line2 = AllLines[j];
                    if (line1 == line2) { continue; }
                    if (line1.EndPointKey.Equals(line2.StartPointKey))
                    {
                        line1.NextLines.Add(line2);
                    }
                }
                if(line1.NextLines.Count == 0)
                {

                }
            }

        }
        class PointCluster
        {
            public PointF Center;
            public double AllX;
            public double AllY;
            public List<PointInfo> PS = new List<PointInfo>();
            public bool IsDisposed=false;

            public PointCluster(PointF startPoint,int lineIndex,bool IsStart)
            {
                this.Center = startPoint;
                PS.Add(new PointInfo()
                {
                    P=startPoint, LineIndex=lineIndex,IsStart=IsStart
                });
                AllX = startPoint.X;
                AllY = startPoint.Y;
            }

            public void AddPoint(PointInfo np)
            {
                PS.Add(np);
                AllX += np.P.X;
                AllY += np.P.Y;
                Center.X = (float)(AllX / PS.Count);
                Center.Y = (float)(AllY / PS.Count);
            }

            internal void Union(PointCluster pointCluster)
            {
                for(var i = 0; i < pointCluster.PS.Count; i++)
                {
                    AddPoint(pointCluster.PS[i]);
                }
                pointCluster.IsDisposed = true;
            }

            public override string ToString()
            {
                return PS.Count.ToString();
            }
        }
        class PointInfo
        {
            public PointF P;
            public int LineIndex;
            public bool IsStart;
        }

        public void Clear()
        {
            m_allLines.Clear();
        }

        internal void Render(Graphics g,Font font, bool showConnection)
        {
            for (var i = 0; i < AllLines.Count; i++)
            {
                g.DrawLine(Pens.Blue, AllLines[i].StartPoint, AllLines[i].EndPoint);
                if(showConnection)
                    g.DrawString(AllLines[i].NextLines.Count.ToString(), font, Brushes.Red, AllLines[i].EndPoint);
            }
                
            for (var i = 0; i < AllNodes2.Count; i++)
                g.DrawEllipse(Pens.Green, AllNodes2[i].X - 2, AllNodes2[i].Y - 2, 4, 4);
        }
    }
}
